package br.com.controleVendas.dao;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;

import br.com.controleVendas.config.HibernateUtil;
import br.com.controleVendas.entity.GenericEntity;
import br.com.controleVendas.utils.ReflectionUtils;

@SuppressWarnings("rawtypes")
public class GenericDao<T extends GenericEntity, D extends T>
{

    Session session;

    protected Session getSession()
    {
        return HibernateUtil.getInstance().getSession();
    }

    @SuppressWarnings("unchecked")
    public List<D> getList(D ob)
        throws Exception
    {

        session = getSession();
        Criteria c = session.createCriteria(ob.getClass().getSuperclass());
        ReflectionUtils.prepareCriteria(ob, c, false);

        if(ob.getListCriterion() != null && !ob.getListCriterion().isEmpty())
            for(Criterion cOb : ((GenericEntity<T>) ob).getListCriterion())
                c.add(cOb);
        
        if(ob.getListOrder() != null && !ob.getListOrder().isEmpty())
            for(Order cOrder : ((GenericEntity<T>) ob).getListOrder())
                c.addOrder(cOrder);

        List<T> list = c.list();
        List<D> result = new ArrayList<>();
        if(list != null && !list.isEmpty())
            for(T t : list)
                result.add((D) ReflectionUtils.cloneToDto(t));

        session.close();
        return result;
    }

    @SuppressWarnings("unchecked")
    public D getOne(D ob)
        throws Exception
    {
        session = getSession();
        session.beginTransaction();

        Criteria c = session.createCriteria(ob.getClass().getSuperclass());
        ReflectionUtils.prepareCriteria(ob, c, false);

        if(ob.getListCriterion() != null && !ob.getListCriterion().isEmpty())
            for(Criterion cOb : ((GenericEntity<T>) ob).getListCriterion())
                c.add(cOb);

        if(ob.getListOrder() != null && !ob.getListOrder().isEmpty())
            for(Order cOrder : ((GenericEntity<T>) ob).getListOrder())
                c.addOrder(cOrder);

        List<T> list = c.setMaxResults(1).list();
        
        if(list != null && !list.isEmpty())
        {
            D result = (D) ReflectionUtils.cloneToDto(list.get(0));
            session.close();
            return result;
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public D salvar(D ob)
        throws Exception
    {
        D result = (D) ob.getClass().newInstance();
        ReflectionUtils.set(result, "cdId", ReflectionUtils.get(saveOrUpdate(ob), "cdId"));

        return result;
    }

    @SuppressWarnings("unchecked")
    protected T saveOrUpdate(D ob)
        throws Exception
    {
        session = getSession();

        T t = (T) ReflectionUtils.cloneToEntity(ob);

        session.beginTransaction();
        session.saveOrUpdate(t);
        session.flush();
        session.getTransaction().commit();
        session.close();

        return t;
    }

    @SuppressWarnings("unchecked")
    public void remove(D ob)
        throws Exception
    {
        session = getSession();

        T t = (T) ReflectionUtils.cloneToEntity(ob);

        session.beginTransaction();
        session.delete(t);
        session.flush();
        session.getTransaction().commit();
        session.close();
    }
}
